home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / pctchnqs / 1992 / number2 / rtcbios.c < prev    next >
C/C++ Source or Header  |  1992-04-16  |  12KB  |  320 lines

  1. #pragma inline
  2. /*
  3.  * RTCBIOS.C
  4.  * Interface module for the AT real-time clock functions 2
  5.  * through 7 and BIOS interrupt 15H functions 83H and 86H.
  6.  *
  7.  * Author Jim Mischel */
  8. #include <dos.h>
  9. #include <bios.h>
  10. #include "rtcbios.h"
  11. #define TESTING       /* comment this if compiling for library */
  12.  
  13. #define ALARM 0x4A
  14.  
  15. /* SetWait -- Set a wait interval in microseconds.
  16.  *  The interval is rounded up to the next multiple
  17.  *  of 976 microseconds.
  18.  *  At the end of the interval, the high bit or the byte
  19.  *  pointed to by Flag will be set.
  20.  *  Returns 0 if wait set successfully
  21.  *          1 if unable to set wait interval */
  22. int SetWait (long ms, unsigned char far *Flag) {
  23.     char Status;
  24.     *Flag &= 0x7f;                               /* clear flag */
  25.     asm mov ax,8300h
  26.     asm mov cx,[word ptr ms+2]     /* CX:DX = wait interval... */
  27.     asm mov dx,[word ptr ms]             /* ...in microseconds */
  28.     asm les bx,[Flag]                 /* ES:BX=address of flag */
  29.     asm clc                                    /* clear status */
  30.     asm int 15h                                /* set the wait */
  31.     asm lahf                              /* put flags into AH */
  32.     asm and ah,1                     /* get Carry flag (bit 0) */
  33.     asm mov [Status],ah                      /* save status... */
  34.     return Status;                              /* ...and exit */
  35. }
  36.  
  37. /* CancelWait -- Cancel wait interval set by SetWait. */
  38. void CancelWait (void) {
  39.     asm mov ax,0040h
  40.     asm mov es,ax                    /* ES = BIOS data segment */
  41.     asm cli                               /* no interruptions! */
  42.     asm xor ax,ax                                  /* clear... */
  43.     asm mov [byte ptr es:00A0h],al      /* Wait Active flag... */
  44.     asm mov [word ptr es:009Ch],ax            /* ...LSB and... */
  45.     asm mov [word ptr es:009Eh],ax        /* MSB of Wait Count */
  46.     asm sti
  47. }
  48.  
  49. /* Wait -- Delay execution for a number of microseconds.
  50.  *  Wait interval is rounded up to the next multiple
  51.  *  of 976 microseconds.
  52.  *  Returns 0 if wait successful
  53.  *          1 if unable to wait for the interval */
  54. int Wait (long ms) {
  55.     char Status;
  56.     asm mov ah,86h
  57.     asm mov cx,[word ptr ms+2]     /* CX:DX = wait interval... */
  58.     asm mov dx,[word ptr ms]             /* ...in microseconds */
  59.     asm int 15h                                 /* do the wait */
  60.     asm lahf                              /* get flags into AH */
  61.     asm and ah,1                     /* Carry flag is bit 0... */
  62.     asm mov [Status],ah               /* ...and save as Status */
  63.     return Status;
  64. }
  65.  
  66. /* BCDtoBin - Convert BCD value (0-99) to binary */
  67. static int BCDtoBin (int BCD) {
  68.     return (BCD >> 4)*10 + (BCD & 0xf);
  69. }
  70.  
  71. /* Convert binary value (0-99) to BCD */
  72. static int BinToBCD (int Bin) {
  73.     return ((Bin / 10) << 4) + (Bin % 10);
  74. }
  75.  
  76. /* GetRTCtime -- Get current RTC time & place in Time structure.
  77.  *   Returns 0 -- function successful
  78.  *           1 -- unable to read time (Time invalid) */
  79. int GetRTCtime (struct RTCTIME far *Time) {
  80.     char Status;
  81.     asm mov ah,2                     /* Read RTC time function */
  82.     asm clc                          /* clear status indicator */
  83.     asm int 1ah                            /* go read the time */
  84.     asm lahf                                /* get flags to AH */
  85.     asm and ah,1                /* get status of carry flag... */
  86.     asm mov [Status],ah              /* ...and store in Status */
  87.     asm jnz around                  /* if not successful, skip */
  88.     asm les di,[Time]     /* ES:DI = address of time structure */
  89.     asm xor ah,ah
  90.     asm mov [es:di+6],ax                 /* save daylight flag */
  91.     asm mov al,ch
  92.     asm cld
  93.     asm stosw                                      /* Hour,... */
  94.     asm mov al,cl
  95.     asm stosw                                 /* ...Minute,... */
  96.     asm mov al,dh
  97.     asm stosw                                 /* ...and Second */
  98.   /* -- Convert returned time from BCD to binary -- */
  99.     Time->Hour = BCDtoBin (Time->Hour);
  100.     Time->Min = BCDtoBin (Time->Min);
  101.     Time->Sec = BCDtoBin (Time->Sec);
  102. around:
  103.     return Status;
  104. }
  105.  
  106. /* SetRTCtime -- Set current time from Time structure
  107.  *   Returns 0 -- function successful
  108.  *           1 -- unable to set time (Time invalid) */
  109. int SetRTCtime (struct RTCTIME *Time) {
  110.     char Status;
  111.     struct RTCTIME WorkTime;
  112.   /* -- Convert Time to BCD in WorkTime -- */
  113.     WorkTime.Hour = BinToBCD (Time->Hour);
  114.     WorkTime.Min = BinToBCD (Time->Min);
  115.     WorkTime.Sec = BinToBCD (Time->Sec);
  116.     WorkTime.Daylight = Time->Daylight;
  117.     asm mov ah,3                      /* set RTC Time function */
  118.     asm mov ch,[WorkTime.Hour]
  119.     asm mov cl,[WorkTime.Min]
  120.     asm mov dh,[WorkTime.Sec]
  121.     asm mov dl,[WorkTime.Daylight]
  122.     asm clc
  123.     asm int 1ah
  124.     asm lahf                                /* get flags to AH */
  125.     asm and ah,1                     /* carry flag is bit 0... */
  126.     asm mov [Status],ah              /* ...and store in Status */
  127.     return Status;
  128. }
  129.  
  130. /* GetRTCdate -- Get RTC date and place in Date structure.
  131.  *  Returns 0 -- function successful
  132.  *          1 -- unable to read date */
  133. int GetRTCdate (struct RTCDATE far *Date) {
  134.     char Status;
  135.     asm mov ah,4                      /* Get RTC date function */
  136.     asm clc                          /* clear status indicator */
  137.     asm int 1ah                            /* go read the date */
  138.     asm lahf                                /* get flags to AH */
  139.     asm and ah,1                /* get status of carry flag... */
  140.     asm mov [Status],ah              /* ...and store in Status */
  141.     asm jnz around                  /* if not successful, skip */
  142.     asm les di,[Date]     /* ES:DI = address of date structure */
  143.     asm xor ax,ax
  144.     asm cld
  145.     asm mov al,ch
  146.     asm stosw                              /* Save century,... */
  147.     asm mov al,cl
  148.     asm stosw                                   /* ...year,... */
  149.     asm mov al,dh
  150.     asm stosw                                  /* ...month,... */
  151.     asm mov al,dl
  152.     asm stosw                                    /* ...and day */
  153.   /* -- Convert returned date from BCD to binary -- */
  154.     Date->Century = BCDtoBin (Date->Century);
  155.     Date->Year = BCDtoBin (Date->Year);
  156.     Date->Month = BCDtoBin (Date->Month);
  157.     Date->Day = BCDtoBin (Date->Day);
  158. around:
  159.     return Status;
  160. }
  161.  
  162. /* SetRTCdate -- Set RTC date from Date structure
  163.  *   Returns 0 -- function successful
  164.  *           1 -- unable to set date */
  165. int SetRTCdate (struct RTCDATE *Date) {
  166.     char Status;
  167.     struct RTCDATE WorkDate;
  168.   /* -- Convert Date to BCD in WorkDate -- */
  169.     WorkDate.Century = BinToBCD (Date->Century);
  170.     WorkDate.Year = BinToBCD (Date->Year);
  171.     WorkDate.Month = BinToBCD (Date->Month);
  172.     WorkDate.Day = BinToBCD (Date->Day);
  173.     asm mov ah,5                      /* set RTC Date function */
  174.     asm mov ch,[WorkDate.Century]
  175.     asm mov cl,[WorkDate.Year]
  176.     asm mov dh,[WorkDate.Month]
  177.     asm mov dl,[WorkDate.Day]
  178.     asm clc
  179.     asm int 1ah
  180.     asm lahf                                /* get flags to AH */
  181.     asm and ah,1                     /* carry flag is bit 0... */
  182.     asm mov [Status],ah              /* ...and store in Status */
  183.     return Status;
  184. }
  185.  
  186. /* SetAlarm -- Set the user alarm from the Time structure and
  187.  *   install the alarm interrupt service routine.
  188.  *   Returns 0 if alarm set successfully
  189.  *           1 if unable to set alarm. */
  190. int SetAlarm (struct RTCTIME *Time,
  191.         void interrupt (*AlarmInt)()) {
  192.     char Status;
  193.     struct RTCTIME WorkTime;
  194.   /* -- Convert Time to BCD in WorkTime -- */
  195.     WorkTime.Hour = BinToBCD (Time->Hour);
  196.     WorkTime.Min = BinToBCD (Time->Min);
  197.     WorkTime.Sec = BinToBCD (Time->Sec);
  198.     asm mov ah,6                         /* set alarm function */
  199.     asm mov ch,[WorkTime.Hour]
  200.     asm mov cl,[WorkTime.Min]
  201.     asm mov dh,[WorkTime.Sec]
  202.     asm clc                    /* fixes problem with some BIOS */
  203.     asm int 1ah
  204.     asm lahf                                /* get flags to AH */
  205.     asm and ah,1                     /* carry flag is bit 0... */
  206.     asm mov [Status],ah              /* ...and store in Status */
  207.     if (!Status)
  208.     setvect (ALARM, AlarmInt);             /* install new ISR */
  209.     return Status;
  210. }
  211.  
  212. /* ClearAlarm -- Cancel alarm set by SetAlarm */
  213. void ClearAlarm (void) {
  214.     asm mov ah,7
  215.     asm int 1ah
  216. }
  217.  
  218. /*** Test code ***/
  219. #ifdef TESTING
  220. #include <stdio.h>
  221.  
  222. #define ESC 0x011B
  223. volatile int TimeOut;                 /* Flag set by alarm ISR */
  224. void interrupt (*OldAlarmInt) (void) = NULL;  /* old alarm ISR */
  225.  
  226. /* AlarmInterrupt -- Sets the TimeOut flag and returns */
  227. void interrupt AlarmInterrupt (void) {
  228. #ifdef __TINY__
  229.     asm extrn DGROUP@      /* Fix problem with TC++ Tiny model */
  230. #endif
  231.     TimeOut = 1;
  232. }
  233.  
  234. /* Make a simple sound effect */
  235. void SoundAlarm (void) {
  236.     static int FreqTable[] = {238,265,298,341,398,477,597,0};
  237.     int Freq;
  238.     for (Freq = 0; FreqTable[Freq] != 0; Freq++) {
  239.     sound (FreqTable[Freq]);
  240.     Wait (300000L/(Freq+1));
  241.     }
  242.     nosound ();
  243. }
  244.  
  245. void main (void) {
  246.     unsigned char KeyFlag;             /* flag used by SetWait */
  247.     int ch;                      /* dummy variable to read key */
  248.     struct RTCTIME Time;
  249.     struct RTCDATE Date;
  250.  
  251.     /* Part 1 -- test Wait, SetWait, CancelWait */
  252.     do {
  253.     KeyFlag = 0;
  254.     while (bioskey (1))              /* empty keyboard buffer */
  255.         ch = bioskey (0);
  256.  
  257.    /* -- 2.5 second wait interval -- */
  258.     if (SetWait (2500000L, &KeyFlag))
  259.         puts ("Unable to set wait interval");
  260.     printf ("Press any key.\n"
  261.         "Press ESC to move to 2nd part of test: ");
  262.     ch = bioskey (0);                   /* wait for character */
  263.     CancelWait ();                    /* cancel wait interval */
  264.     if (KeyFlag & 0x80)             /* wait interval expired? */
  265.         puts ("Key pressed AFTER wait interval expired.\n");
  266.     else
  267.         puts ("Key pressed during wait interval.\n");
  268.     if (Wait (1000000L))                    /* 1-second delay */
  269.         puts ("Wait error");
  270.     } while (ch != ESC);                     /* loop until ESC */
  271. /* Part 2: Test GetRTCtime, GetRTCdate, SetAlarm, ClearAlarm   */
  272.     if (GetRTCdate (&Date))
  273.     puts ("Unable to read RTC date");
  274.     else
  275.     printf ("Today is %02d/%02d/%02d%02d\n",
  276.         Date.Month, Date.Day, Date.Century, Date.Year);
  277.     if (GetRTCtime (&Time))
  278.     puts ("Unable to read RTC time");
  279.     else {
  280.     printf ("The time is %02d:%02d:%02d\n",
  281.         Time.Hour, Time.Min, Time.Sec);
  282.     if (Time.Daylight > 1)
  283.         puts ("Status of daylight savings "
  284.             "flag is undetermined");
  285.     else
  286.         printf ("Daylight savings time %s in effect\n",
  287.             (Time.Daylight) ? "is" : "is not");
  288.    /* -- add 30 seconds to the current time -- */
  289.     Time.Sec = Time.Sec + 30;
  290.     if (Time.Sec > 59) {
  291.         Time.Sec -= 60;
  292.         if (++Time.Min > 59) {
  293.         Time.Min -= 60;
  294.         if (++Time.Hour > 23)
  295.             Time.Hour -= 24;
  296.         }
  297.     }
  298.     OldAlarmInt = getvect (ALARM);      /* Save old alarm int */
  299.     TimeOut = 0;
  300.     if (SetAlarm (&Time, AlarmInterrupt))
  301.         puts ("Unable to set alarm");
  302.     else {
  303.         printf ("Alarm will sound at %02d:%02d:%02d\n",
  304.             Time.Hour, Time.Min, Time.Sec);
  305.         puts ("Press any key to exit"
  306.           " before alarm sounds");
  307.         while (!TimeOut) {                  /* Wait for alarm */
  308.         if (bioskey (1)) {                 /* if key pressed */
  309.             bioskey (0);                      /* read key... */
  310.             break;                       /* ...and exit loop */
  311.         }
  312.         }
  313.         SoundAlarm ();                     /* sound the alarm */
  314.         ClearAlarm ();                      /* turn alarm off */
  315.     }
  316.     setvect (ALARM, OldAlarmInt);          /* reset alarm int */
  317.     }
  318. }
  319. #endif TESTING
  320.